package backtype.storm.transactional;

import java.math.BigInteger;
import java.util.Map;

import backtype.storm.coordination.BatchOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.IComponent;


public interface ITransactionalSpout<T> extends IComponent {
    public interface Coordinator<X> {
        /**
         * Create metadata for this particular transaction id which has never
         * been emitted before. The metadata should contain whatever is
         * necessary to be able to replay the exact batch for the transaction at
         * a later point.
         * 
         * The metadata is stored in Zookeeper.
         * 
         * Storm uses the Kryo serializations configured in the component
         * configuration for this spout to serialize and deserialize the
         * metadata.
         * 
         * @param txid
         *            The id of the transaction.
         * @param prevMetadata
         *            The metadata of the previous transaction
         * @return the metadata for this new transaction
         */
        X initializeTransaction(BigInteger txid, X prevMetadata);


        /**
         * Returns true if its ok to emit start a new transaction, false
         * otherwise (will skip this transaction).
         * 
         * You should sleep here if you want a delay between asking for the next
         * transaction (this will be called repeatedly in a loop).
         */
        boolean isReady();


        /**
         * Release any resources from this coordinator.
         */
        void close();
    }

    public interface Emitter<X> {
        /**
         * Emit a batch for the specified transaction attempt and metadata for
         * the transaction. The metadata was created by the Coordinator in the
         * initializeTranaction method. This method must always emit the same
         * batch of tuples across all tasks for the same transaction id.
         * 
         * The first field of all emitted tuples must contain the provided
         * TransactionAttempt.
         * 
         */
        void emitBatch(TransactionAttempt tx, X coordinatorMeta, BatchOutputCollector collector);


        /**
         * Any state for transactions prior to the provided transaction id can
         * be safely cleaned up, so this method should clean up that state.
         */
        void cleanupBefore(BigInteger txid);


        /**
         * Release any resources held by this emitter.
         */
        void close();
    }


    /**
     * The coordinator for a TransactionalSpout runs in a single thread and
     * indicates when batches of tuples should be emitted and when transactions
     * should commit. The Coordinator that you provide in a TransactionalSpout
     * provides metadata for each transaction so that the transactions can be
     * replayed.
     */
    Coordinator<T> getCoordinator(Map conf, TopologyContext context);


    /**
     * The emitter for a TransactionalSpout runs as many tasks across the
     * cluster. Emitters are responsible for emitting batches of tuples for a
     * transaction and must ensure that the same batch of tuples is always
     * emitted for the same transaction id.
     */
    Emitter<T> getEmitter(Map conf, TopologyContext context);
}
